Backend.php

<?php

namespace Tlf\User;

use Cartalyst\Sentinel\Native\Facades\Sentinel;

/**
 * A wrapper for all things Sentinel, so this SHOULD be the ONLY place that has a reference to Sentinel
 */
class Backend {

    protected $capsule;
    protected $core;
    protected $package;

    public function __construct(\Lia\Compo $core){
        $this->core = $core;
        $this->package = $core->package;
    }

    public function getPdo(){
        $pdo = new \PDO($this->package->get('DB.driver')
                            .':host='.$this->package->get('DB.host').';dbname='.$this->package->get('DB.database'),
                        $this->package->get('DB.user'), $this->package->get('DB.password')
                );
        return $pdo;
    }
    //
    // global stuffs
    //
    public function connectDb(){
        $package = $this->package;
        $capsule = new \Illuminate\Database\Capsule\Manager;
        $capsule->addConnection($dbInfo = [
            'driver'    => $package->get('DB.driver'),
            'host'      => $package->get('DB.host'),
            'charset'   => $package->get('DB.charset'),
            'collation' => $package->get('DB.collation'),
            
            'database'  => $package->get('DB.database'),
            'username'  => $package->get('DB.user'),
            'password'  => $package->get('DB.password'),
        ]);
        
        $capsule->bootEloquent();
        $this->capsule = $capsule;
    }
    public function getSqlCreate(){
        $createSql = file_get_contents($package->dir().'/files/sentinel-db.sql');
        return $createSql;
    }


    //
    // user information
    //
    public function updateUserFirstName($model, $newFirstName){
        Sentinel::update($model, ['first_name'=>$newFirstName]);
    }
    public function updateUserLastName($model, $newLastName){
        Sentinel::update($model, ['last_name'=>$newLastName]);
    }
    public function updateUserEmail($model, $newEmail){
        Sentinel::update($model, ['email'=>$newEmail]);
    }
    public function deleteUser($model){
        $model->delete();
    }

    //
    //user state on site
    //
    public function logoutUser(){
        $model = Sentinel::forceCheck();
        if ($model)Sentinel::logout($model);
    }

    public function login($model){
        $didLogin = Sentinel::login($model, true);
        return $didLogin;
    }
    public function logoutEverywhere($model){
        return Sentinel::logout($model, true);
    }

    //
    // user state in backend
    //
    public function register($email, $name, $password){
        $credentials = [
            'email'=>$email,
            'name'=>$name,
            'password'=>$password
        ];
        $model = Sentinel::register($credentials);
        return $model;
    }
    public function setPassword($model, $newPassword){
        return Sentinel::update($model,[
            'password'=>$newPassword
        ]);
    }

    
    //
    //user retrieval
    //
    public function getLoggedInUser(){
        return Sentinel::check();
    }
    public function userFromEmail($email){
        $model = Sentinel::findUserByCredentials(['email'=>$email]);
        return $model;
    }
    public function authenticate($email, $password){
        $model = Sentinel::authenticate(
            [   'email'=>$email,
                'password'=> $password,
            ]
            );
        return $model;
    }
    public function userById($id){
        $model = Sentinel::findUserById($id);
        return $model;
    }

    //
    //activations 
    //
    public function removeActivation($model){
        return Sentinel::getActivationRepository()->remove($model);
    }
    public function newActivationCode($sentinelUser){
        $activation = Sentinel::getActivationRepository()->create($sentinelUser);
        return $activation['code'];
    }

    public function completeActivation($model, $code){
        //@TODO test & make sure that `complete`ing an already complete activation code will return true. Since registration & reset password use the same system (activation codes), and we don't want to de-activate an account when a password reset is requested... we'll be completing an already complete code when someone is changing their password.
        $didActivate = Sentinel::getActivationRepository()->complete($model, $code);
        return $didActivate;
    }
    public function hasCompletedActivation($model){
        if (Activation::completed($model))return true;
        return false;
    }



    //
    // user permissions & roles
    //
    //
    public function getRoles($user){
        if ($user->model()==null)return [];
        $pdo = $this->core->getPdo();
        $query = 
        <<<SQL
            SELECT roles.* FROM roles
                JOIN role_users
                    ON role_users.role_id = roles.id
            WHERE
                role_users.user_id = :user_id
        SQL;
        $st = $pdo->prepare($query);
        $st->execute([':user_id'=>$user->id]);
        return $st->fetchAll(\PDO::FETCH_ASSOC);
    }
    public function getRoleFromSlug($roleName){
        $role = Sentinel::findRoleBySlug($roleName);
        return $role;
    }
    public function createRole($roleName){
        $roleRepo = Sentinel::getRoleRepository();
        $role = $roleRepo->create([
            'name'=>$roleName,
            'slug'=>$roleName
        ]);
        return $role;
    }
    public function addRole($user, $roleName){
        $role = $this->getRoleFromSlug($roleName);
        if ($role==null)$role = $this->createRole($roleName);
        try {
            $role->users()->attach($user->model());
        } catch (\PDOException $e){
            return $role;
        }
        return $role;
    }
    public function getPermissions($user){
        return $user->model()->getPermissions();
    }
    protected function permissionKey($action, $withId){
        if ($withId!=null)$action .= '-'.$withId;
        return $action;
    }

    public function permit($user, $action, $withId=null){
        $action = $this->permissionKey($action,$withId);
        // $user->model()->addPermission($action);
        $user->model()->updatePermission($action, true, true);
        $user->model()->save();
    }
    public function revoke($user, $action, $withId=null){
        $action = $this->permissionKey($action,$withId);
        $user->model()->removePermission($action);
        $user->model()->save();
    }
    public function forbid($user, $action, $withId=null){
        $action = $this->permissionKey($action,$withId);
        $user->model()->updatePermission($action, false, true);
        $user->model()->save();
    }
    public function can($user, $action, $withId=null){
        $action = $this->permissionKey($action,$withId);
        return $user->model()->hasAccess([$action]);
    }
    public function isRole($user, $role){
        if ($user->model()==null)return false;
        $userId = $user->id;

        $role = strtolower($role);

        $pdo = $this->core->getPdo();
        $query =
        <<<SQL
            SELECT roles.slug AS role_slug, roles.id AS role_id, role_users.user_id AS user_id FROM roles
                JOIN role_users ON
                    role_users.role_id = roles.id

                WHERE roles.slug LIKE :slug
                    AND role_users.user_id = :user_id
        SQL;
        $statement = $pdo->prepare($query);
        $statement->execute([':slug'=>$role, ':user_id' => $userId]);

        $rows = $statement->fetchAll(\PDO::FETCH_ASSOC);
        if (count($rows)<1)return false;
        $r = $rows[0];
        if (strtolower($r['role_slug'])==$role
            && $r['user_id']==$userId
            && $r['role_id']!=null
        ) {
            return true;
        }
        return false;

    }

}